<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JS学习笔记</title>
    <style>
        body {
            line-height: 1.5;
        }

        p {
            color: red;
        }
    </style>
</head>

<body>
    <h2>JS学习</h2>
    <h4>一、编程语言（Programming Language）</h4>
    <p>来控制一系列指令，有固定的格式和词汇（不同编程语言和词汇不一样），必须遵守</p>
    <p>
        1.编程:<br>
        （1）就是计算机为解决某个问题而使用某种程序设计语言编写代码，最终得到结果的过程<br>
        （2）计算机程序：<br>
        就是计算机所执行的一系列 指令集合 ，而程序全部都是用我们所掌握的语言来编写的，所以人们要控制计算机一定要通过计算机语言向计算机发出命令<br>
        （3）注意：<br>
        上面所定义的计算是指 任何能够执行代码的设备 ，可能是智能手机、ATM机、黑莓PI、服务器等等<br>
        （4）计算机语言：<br>
        指用于 人与计算机之间通讯的语言 ，它是人与计算机之间传递信息的 媒介 。<br>
        计算机语言总的来说分为三大类： 机器语言、 汇编语言、 高级语言<br>
        机器语言：实际上计算机最终所执行的，它由“0”和“1”组成的二进制， 二进制是计算机语言的基础 。<br>
        汇编语言：和机器语言实质相同，都是直接对硬件操作，只不过指令采用了英文缩写的标识符，容易识别和记忆（相对也难）<br>
        高级语言：主要是相对于低级语言而言，并不是指某一种具体的语言，而是包括了很多编程语言，常用的有C语言、C++、java、C#、Python、PHP、JavaScript、GO语言、Objective-C、Swift等<br>
        （4）翻译器：<br>
        可以将我们所编写的源代码转为机器语言，这也称为二进制化。记住1和0。<br>
        （5）编程语言和标记语言区别：<br>
        编程语言：有很强的逻辑和行为能力。在编程语言里，会有很多if else、for、while等逻辑性和行为能力的指令，这是主动的<br>
        标记语言（html）：不用与向计算机发出指令，常用于格式化和链接，标记语言存在是用来读取的，它是被动语言<br>
    </p>
    <h4>二、JS初识</h4>
    <p>
        1.JS<br>
        发明人：布莱登·艾奇，利用10天完成JS设计，网景公司最初叫LiveScript，后来和Sun合作改名JS<br>
        JS是一种 运行在客户端的脚本语言<br>
        脚本语言：不需要编译，运行过程中由JS解释器（js引擎）逐行来进行解释并执行<br>
        现在也可以给予Node.js技术进行服务器端编程<br>
        JS作用：<br>
        表单动态效验（密码强度检测）（JS产生最初的目的）<br>
        网页特效<br>
        服务端开发（Node.js）<br>
        桌面程序（Electron）<br>
        App（Cordova）<br>
        控制硬件-物联网（Ruff）<br>
        游戏开发（cocos2d-js）<br>
        （2）浏览器执行JS<br>
        浏览器分为两部分 渲染引擎 和 JS引擎<br>
        渲染引擎：用来解析HTML和CSS，俗称内核，比如chrome浏览器的blink，老版本的webkit<br>
        JS引擎：也称JS解释器，用来读取网页中的JS代码，对其处理后运行，比如Chrome浏览器的V8<br>
        **注意：<br>
        浏览器本身并不会执行JS代码，二回通过内置的JS引擎（解释器）来执行JS代码。JS引擎执行代码时逐行解释每一句源码（转化为机器语言），然后计算机去执行，所以JS语言归为脚本语言，会逐行解释执行<br>
        （3）JS的组成<br>
        JS语法（ECMAscript）、DOM（页面文档对象模型）、BOM（浏览器对象模型）<br>
        ECMAscript：规定了js的编程语法和基础核心，是所有浏览器厂商共同遵守的一套JS语法工业标准<br>
        DOM：是W3C组织推荐的处理可扩展标记语言的 标准编程借口 ，通过DOM提供的接口可以对页面上各种元素进行操作（大小、位置、颜色等）<br>
        BOM:它提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。通过BOM可以操作浏览器窗口，比如弹出框、控制浏览器的跳转、获取分辨率等<br>

    </p>
    <p>
        2.JS初体验<br>
        （1）三种书写位置，分别为 行内 、内嵌 、 外部<br>
        注意：<br>
        JS推荐使用单引号''<br>
        引入JS文件的script双标签中间绝对不可以写代码<br>
        （2）JS注释<br>
        单行注释：// 一行 快捷键：Ctrl+/<br>
        多行注释：/* 第一行 第二行 */ 快捷键：shift+alt+a<br>
    </p>
    <p>
        3.JS输入输出语句<br>
        alert(msg):浏览器弹出警示框，归属：浏览器<br>
        console.log(msg):浏览器控制打印输出信息，归属：浏览器<br>
        prompt(info):浏览器弹出输入框，用户可以输入，归属：浏览器<br>
    </p>
    <h4>三、变量</h4>
    <p>
        1.白话：变量就是一个装东西的盒子<br>
        通俗：变量用于存放数据的容器，通过变量名获取数字，甚至数据可以修改<br>
        本质：变量是程序在 内存 中申请一块用来 存放数据 的空间<br>
    </p>
    <p>
        2.变量的使用<br>
        两步：先 声明变量var ，然后 赋值<br>
        （1）语法 var 自己需要的名字 = 赋值；<br>
        （2）声明变量（variable）<br>
        var age；：声明一个 名称为age的变量<br>
        （3）赋值<br>
        var age = 10；：给age这个变量赋值为10<br>
        "="符号 用来把右边的值赋给左边的变量空间中，此处代表赋值的意思<br>
        变量值是程序员保存到变量空间去<br>
    </p>
    <p>
        3.变量语法扩展<br>
        （1）更新变量<br>
        一个变量被重新赋值后，它原有的值就会被覆盖，变量值将以最后ICI付的值为准<br>
        （2）声明多个变量<br>
        只写一个var，多个变量用“，”逗号隔开，最后一个再加分号<br>
        （3）声明变量的特殊情况<br>
        只声明不赋值 程序也不知道里面存的什么 所以结果 是 undefined(未定义的)<br>
        不赋值 只输出 直接使用某个未知变量 会报错 而且导致计算机程序不往下读取后面<br>
        不声明 直接赋值使用 可以输出，但是不提倡此方法<br>
    </p>
    <p>
        4.变量命名规范<br>
        （1）由字母（a-z/A-Z）、数字（0-9）、下划线（_）、美元符号（$）组成。如：usrAge，num01，_name<br>
        （2）遵循驼峰规范命名法，首字母小写，后面单词的首字母需要大写。如：myFristName<br>
        （3）严格区分大小写。例如var app和var App是两个变量<br>
        （4）不能以数字开头。如：18age，错误的<br>
        （5）不能 是关键字、保留字。如：var、for、while if<br>
        （6）变量名必须有意义,不要用中文拼音简写。如：MMD BBD NL<br>
        注意：不要直接使用 name 作为变量名<br>
    </p>
    <p>
        5.临时变量<br>
        js 是编程语言 有很强的逻辑性：实现这个要求的思路 先什么做 后怎么做<br>
        声明了一个临时变量 为空<br>
        把右边给左边（接收方的写左边）<br>
    </p>
    <h4>四、数据类型</h4>
    <p>
        （1）不同的数据所需占用的存储空间不同的，为了充分利用空间，于是定义了不同的数据类型<br>
        （2）JS是 弱类型 或者 动态语言，不用提前声明变量类型，在程序运行过程中，类型根据右边的赋值会自动确定<br>
    </p>
    <p>
        1.数据类型的分类<br>
        简单数据类型：（Number、String、Boolean、Undefined、Null）<br>
    </p>
    <p>
        （1）Number:数字型，包含整型值和浮点型值，如21、0.21 默认值是0<br>
        *注意：八进制：0~7 数字前面要写0，如：010=就表示8；<br>
        十六进制：0~9 a~f 数字前面要写0x，如：0x9=就表示9；<br>
        js里数值的最大值 和 最小值: （Number.MAX_VALUE）/（Number.MIN_VALUE）;<br>
        infinity：无穷大；-infinity：无穷小；NaN:not a number，非数值<br>
        isNaN():这个方法用来判断是否为数字类型 并返回一个值 如果是数字 返回的是false 如果不是数字 返回的是true<br>
    </p>
    <p>
        （2）String：字符串型，如'张三'，注意js里，字符串都要带引号 默认值''引号<br>
        注意：引号嵌套时，用 外单内双 如：var str = '我是学习"web"前端开发';<br>
        字符串转义符<br>
        都要写到引号内： \n：换行符；\\：斜杠\；\'：单引号；\"：双引号；\t：缩进；\b：空格。<br>
        字符串长度：length<br>
        字符串拼接：+;口诀：数值相加，字符相连<br>
        字符串拼接加强：+ 变量不要写的字符串里面 是通过和字符串拼接相连的方式实现的;口诀：引引加加<br>
    </p>
    <p>
        （3）Boolean：布尔值类型，如ture、false，默认值是false<br>
        注意：在参与加法运算时，等价于1和0<br>
        （4）Undefined：var a；声明了变量a 但是没有赋值，此时输出显示undefined，默认值undefined<br>
        注意：undefined和数字相加，结果是NaN<br>
        （5）Null：var a = Null; 声明了变量a为控制 认值是null<br>
        注意 Null和数字相加 输出结果是原来的数字<br>
    </p>
    <P>
        （6）获取变量数据类型<br>
        typeof：检测变量数据类型<br>
        颜色区别：//蓝色是数字型；//黑色是字符串型；//深蓝是布尔型；//浅灰 未定义；//浅灰 空值<br>
        （7）字面量<br>
        是源码中一个固定值得表示法，通俗说，就是表示如何表达这个值<br>
        数字字面量：8,9,10<br>
        字符串字面量：'web'，'前端开发'<br>
        布尔字面量：true，false<br>
    </P>
    <p>
        2.数据型转换<br>
        使用表、prompt获取过来的数据默认是字符串型的，此时不能直接简单的进行加法运算，所以需要转换<br>
        通俗来说：把 一种数据类型变量转换成另一种数据类型<br>
        三种类型：转换为字符串型、转换为数字型、转换为布尔型<br>
    </p>
    <p>
        （1）转换字符串型<br>
        三种方式：<br>
        toString();：变量.toString（）。例如：var num = 1; alert(num.toString());<br>
        String();：强制转换。例如：var num = 1; alert(String());<br>
        **隐式转换（+拼接字符串）：利用和字符串拼接。例如：var num = 1; alert(num+'字符串型'）;<br>
    </p>
    <p>
        （2）转换数字型（重点）<br>
        四种方式：<br>
        **parseInt(string)函数：将string转成整数数值型。例如：parseInt('78')<br>
        **parseFloat(string)函数：将string转成浮点数数值型。例如：parseFloat('78.21')<br>
        Number()强制转换函数：将string转换为数值型。例如：Number('12')<br>
        js隐式转换（- * /）：利用算术转换为数值型。例如'12'- 0<br>
        （3）转化为布尔型<br>
        方式：Boolean()函数：其他类型转换为布尔值 例如：Boolean('true')<br>
        代表 空值 、 否定类的值 都会转化为false。例如：引号''、0、NaN、null、undefined<br>
        其余的都转化为true。<br>
    </p>
    <h4>五、运算符</h4>
    <p>
        1.算数运算符<br>
        使用符号，用于两个变量或值得算数运算<br>
        （1）+ - * / ：加 减 乘 除；<br>
        （2）取余数（取模），例如：9 % 2 = 1<br>
        用途：它的余数是0说明这个数能被整除，这就是%取余运算符的主要用途<br>
    </p>
    <p>
        2.表达式和返回值<br>
        （1）表达式：是由数字、运算符、变量等组成的式子<br>
        （2）返回值：表达式最终都会有一个结果，返回给我们<br>
        注意：就是 通过右边的表达式计算完毕，把返回值赋予左边 简单理解2=1+1<br>
    </p>
    <p>
        3.递增和递减运算符<br>
        如果需要反复给数字变量添加或者减去，可以使用 递增（++）和 递减（--）运算符来完成<br>
        （++）和（--）放在变量前面，称为前置递增（递减）运算符；反正放在后面，称为后置递增（递减）运算符<br>
        注意：递增和递减运算符，必须和变量配合使用<br>
        （1）前置递增运算符<br>
        写在变量的前面，例如：++num；<br>
        *口诀：先自加，后返回值<br>
        （2）后置递增运算符<br>
        写在变量后面，例如num++<br>
        *口诀：先返回原来的值，再自加<br>
    </p>
    <p>
        3.比较运算符<br>
        也称关系运算符，是 两个数据进行比较时所使用的运算符 ，比较运算后，会返回一个布尔值（true/false）作为比较结果<br>
        （1）大于＞（大于等于＞=）/小于＜（小于等于＜=）；<br>
        （2）==：判断号（会转型，隐形转换）；<br>
        （3）!=：不等号；<br>
        （4）===/!==：全等/全不等 要求 值和数据类型 是否全部都一致；<br>
    </p>
    <p>
        4.逻辑运算符<br>
        概念：用来进行布尔值运算的运算符，其返回值也是布尔值。开发中经常用于多个条件的判断<br>
        （1）"逻辑与&&":，简称“与” and，口诀：有假则假 全真则真<br>
        （2）"逻辑或||": ，简称“或” or，口诀：有真则真 全假则假<br>
        （3）"逻辑非!": ，简称“非” not，!true就是false<br>
    </p>
    <p>
        5.短路运算（逻辑中断）<br>
        原理：当有多个表达式（值）时，左边的表达式值可以确定结果时，就不再继续运算右边的表达式的值<br>
        ***逻辑中断很重要 它会影响程序运行结果***<br>
        （1）逻辑与：<br>
        语法：表达式1 && 表达式2<br>
        如果第一个表达式的值为真，则返回表达式2<br>
        如果第一个表达式为假，则返回表达式1<br>

        （2）逻辑或<br>
        语法：表达式1 || 表达式2<br>
        如果表达式1 结果为真,则返回表达式1<br>
        如果表达式1 结果为假 则返回表达式2<br>
    </p>
    <p>
        6.赋值运算符<br>
        概念：用来把数据赋值给变量的运算符<br>
        （1）=：直接赋值。<br>
        （2）+=、-=：加、减一个数后 再赋值。 例如： var age =10; age+=5; // 15<br>
        （3）*=、/=、%=：乘、除、取模后 再赋值。例如var age =2; age*=5; // 10<br>
    </p>
    <p>
        7.运算符优先等级<br>
        从重到轻：<br>
        （1）小括号：();<br>
        （2）一元运算符：++ 、--、 ! ；<br>
        （3）算数运算符：先 * 、/、 % 后 +、 - ；<br>
        （4）关系运算符：＞、＞=、＜、＜=;<br>
        （5）相等运算符：==、!=、===、!==；<br>
        （6）逻辑运算符：先&&后||;<br>
        （7）赋值运算符：=；<br>
        （8）逗号运算符：，；<br>
    </p>
    <h4>六、流程控制</h4>
    <p>流程控制就是来控制代码按照什么结构顺序来执行<br>
        主要三种结构：<br>
        顺序结构：程序按照 代码的先后顺序，依次执行，大多数的代码都是这样执行。最简单、最基本的流程控制，无特定语法结构，<br>
        分支结构：根据不同的条件，执行不同的路径代码（多选一的过程），得到不同的结果。<br>
        循环结构：可以重复执行某些代码<br>
        代表三种代码执行的顺序。<br>
    </p>
    <h5>分支结构</h5>
    <p>
        1.分支语句-if<br>
        （1）语法：if (条件表达式) {执行语句}<br>
        （2）执行思路：如果 if 里面的 条件表达式 结果为真（true） 则执行大括号里面的 执行语句；<br>
        如果 if 条件表达式为假（false） 则不执行大括号里面的语句 则执行if语句后面的代码。<br>
    </p>
    <p>
        2.双分支语句-if else<br>
        （1）语法：if (条件表达式) {如果条件成立执行语句1} else {“语句1不执行”则执行代码2}<br>
        （2）if里面语句1和else里语句2 根据判断真假，最终只能一个语句执行，2选1<br>
    </p>
    <p>
        3.多分支语句-if else if<br>
        （1）if (条件表达式1) {语句1} else if (条件表达式2) {语句2} else if (条件表达式3) {语句3}...else {“都不满足”执行最后的语句}<br>
        （2）利用多个条件来选择不同的语句执行，得到不同的结果，多选1<br>
    </p>
    <p>
        4.三元表达式-?和:<br>
        （1）语法：条件表达式 ? 表达式1 : 表达式2；<br>
        （2）执行思路：如果条件表达式为真，则返回表达式1的值。如果为假，则返回表达式2的值。<br>
        同理于if else，就是简化版的if else。<br>
    </p>
    <p>
        5.switch语句<br>
        （1）它用于基本不同的条件来执行不同的代码。当要针对变量设计一系列的特定值得选项时，就可以用switch<br>
        （2）语法：<br>
        switch (表达式) {<br>
        case value1:<br>
        执行语句1;<br>
        break;<br>
        case value2:<br>
        执行语句2;<br>
        break;<br>
        ...<br>
        default:<br>
        执行最后的语句;<br>
        }<br>
        （3）执行思路：利用表达式的值 和 case后的选项值相匹配，如果匹配上，就执行case中的语句，<br>
        若都没有匹配上，那么执行default里面的语句<br>
        （4）注意：<br>
        *开发中，表达式经常写成变量<br>
        **表达式的变量 和 case里面的值相匹配的时候 是 全等 必须值和数据类型一致才可以<br>
        ***如果当前的case里没有break，则不会退出switch，会继续执行下一个case<br>
    </p>
    <p>
        6.switch语句和if else if语句的区别<br>
        （1）一般情况下，两者语句可以相互替换<br>
        （2）switch...case语句通常处理case为比较确定值得情况。<br>
        而if else if语句更灵活常用于范围判断（大于、等于某个范围等情况）<br>
        （3）switch语句进行条件判断后直接执行到程序的条件语句，效率更高。<br>
        而if else if语句有几种条件，就会判断多少次<br>
        （4）当分支较少时，if else if语句的执行效率比switch高<br>
        （5）当分支较多时，switch语句执行效率比较高，而且结构更清晰<br>
    </p>
    <h5>****循环结构****</h5>
    <p>
        js中循环结构分为三种：for循环、while循环、do while循环<br>
    </p>
    <p>
        1.for 循环<br>
        一组被重复执行的语句称为 循环体 ，能否继续重复执行，取决于 终止条件<br>
        由循环体及循环的终止条件组成的语句，被称为 循环语句<br>
        （1）语法：<br>
        for (初始化变量; 条件表达式; 操作表达式) {循环体}<br>
        初始化变量：就是用 var声明的一个普通变量，通常用于作为计数器使用的<br>
        条件表达式：就是用来决定每一次循环是否继续执行 就是终止的条件<br>
        操作表达式：就是每次循环最后执行的代码 经常用于我们计数器变量进行更新（递增或者递减）<br>
        （2）执行过程：<br>
        首先执行里面的 计数器变量(初始化变量) ，但是这句话在for循环中，只执行一次<br>
        然后利用 条件表达式 来判断是否满足条件，如果满足条件 就去执行 循环体 不满足条件退出循环<br>
        最后去执行 操作表达式 这是单独写的代码 递增或递减 首轮轮结束<br>
        若有第二轮接着去执行 条件表达式 来判断是否满足条件，如果满足条件 就去执行 循环体 不满足条件退出循环，依次类推<br>
        *****（3）断点调试（自查bug，很重要）：可以帮助我们观察程序的运行过程<br>
        F12-sources-找到需要调试的文件-在程序的某一行设置断点<br>
        watch监视：非常常用，通过watch可以监视变量的值得变化<br>
        F11：程序单步执行，让程序一行一行执行，此时观察watch中变量的值得变化<br>
        （4）for循环重复执行相同代码<br>
        可以让用户控制输出的次数<br>
        （5）for循环重复执行不相同代码<br>
        因为有计数器变量 i 的存在，i 每次循环值都会变化，循环体可以包含别的代码<br>
        （6）for循环重复某些相同操作<br>
        可以做一些算术运算<br>
    </p>
    <p>
        2.双重for循环<br>
        循环嵌套： 在一个循环语句中再定义一个循环语句的语法结构<br>
        例如在for循环中，可以在嵌套一个for循环，这样的for循环称为 双重for循环<br>
        （1）双重for循环 语法结构<br>
        for (外层的初始化变量; 外层的表达式; 外层的操作表达式) {<br>
        for (里层的初始化变量; 里层的条件表达式; 里层的操作表达式) {<br>
        执行语句;<br>
        }<br>
        }<br>
        （2）注意：<br>
        可以把 里层的循环 看做是 外层循环的 语句<br>
        外层的循环 循环一次 里层的循环 执行全部<br>
    </p>
    <p>
        3.while循环<br>
        while：当...时候<br>
        （1）语法结构：while (条件表达式) {循环体;操作表达式}<br>
        （2）执行思路：当条件表达式结果为true 则执行循环体，否则退出循环<br>
        （3）注意：里面也要有计数器 初始化变量<br>
        也要有操作表达式 完成计数器的更新 防止死循环<br>

    </p>
    <p>
        4.do...while循环<br>
        （1）语法结构：do {循环体;操作表达式} while (条件表达式) <br>
        （2）执行思路是while语句的一个变体。该循环先会执行一次代码块，然后对条件表达式进行判断<br>
        如果条件为true，就会重复执行循环体，否则退出循环。<br>
        （3）注意：do...while循环至少会执行一次<br>
    </p>
    <p>
        5.关键字<br>
        （1）continue <br>
        用于 立即跳出 本次循环 ，继续下次循环（本次循环体continue之后的代码就会少执行一次）<br>
        只要遇见continue 退出本次循环 直接退出本次（当前次），跳到操作表达式。继续执行剩余次数循环<br>
        （2）break<br>
        用于退出 整个循环（循环结束）<br>
    </p>
    <h4>七、JS命名规范以及语法格式</h4>
    <p>
        1.标识符命名规范<br>
        （1）变量、函数的命名必须要有意义<br>
        （2）变量的名称一般用名词<br>
        （3）函数的名称一般用动词<br>
        2.操作符命名规范<br>
        （1）操作符的左右两侧各保留一个空格<br>
        （2）特殊就是++ --不用空格<br>
        3.单行注释规范<br>
        （1）// 文字前有空格<br>
        4.其他规范<br>
        （1） () {} 分别两侧留有空格 注意代码对齐<br>
    </p>
    <h4>八、JS数组（Array）</h4>
    <p>
        （1）可以把一组相关的数据一起存放，并提供方便的访问（获取）方式<br>
        （2）一组 数据的集合 ，其中的每个数据都称为 元素， 在数组中可以 存放任意类型的元素<br>
        数组是一种将 一组数据存储在单个变量名 下的优雅方式<br>
    </p>
    <p>
        1.创建数组<br>
        两种方式：利用new创建数组、利用数组字面量创建数组（常用）<br>
        （1）利用new 创建数组<br>
        语法：<br>
        var arr = new Array();<br>
        注意：注意Array A要大写；<br>
        （2）利用数组字面量 创建数组<br>
        []:看到中括号就是字面量数组<br>
        语法:var 数组名=[ ，];<br>
        注意：<br>
        声明数组并赋值称为数组的初始化<br>
        数组里面的数据一定用，逗号分割<br>
        数组里面的数据 称为 数组元素<br>
        数组元素没有限制<br>
    </p>
    <p>
        2.获取数组元素<br>
        （1）数组的索引<br>
        索引（下标）：用来访问数组元素的序号（**数组从0开始**），这里的 访问 就是获取得到的意思<br>
        通过 “数组名[索引]” 来获取数组中的元素<br>
        （2）遍历数组<br>
        遍历：把数组中的每个元素从头到尾访问一次<br>
        利用for循环<br>
        注意：<br>
        因为我们的数组索引号从0开始，所以 计数器 必须从0开始 条件表达式 不能出现等于号<br>
        输出的时候 输入 计数器 即可 计数器 当 索引号 来用<br>
        （3）数组的长度<br>
        数组名.length：可以访问数组元素的数量（数组长度）<br>
        注意：<br>
        数组的长度是元素个数 不要跟索引号混淆<br>
        数组名.length 动态监测数组元素的个数<br>
    </p>
    <p>
        3.数组中新增元素<br>
        两种方法：修改length长度、索引号增加数组元素<br>
    </p>
    <p>
        （1）修改length长度<br>
        实现数组扩容，length属性可读写<br>
        语法：arr.length = 5;<br>
        注意：声明的变量未给值，默认值就是undefined<br>
        （2）索引号增加数组元素<br>
        通过修改数组索引的方式追加数组元素<br>
        语法：arr[] = '';<br>
        注意：<br>
        也可以替换已有的数组元素<br>
        不要直接给数组名赋值，否则会覆盖掉以前的数据<br>
    </p>
    <p>
        4.数组排序（冒泡排序）<br>
        （1）一种算法，一次比较两个元素，如果他们的顺序错误就把他们换过来<br>
        是把一些列的数据按照一定的顺序进行排序显示（从小到大或从大到小）<br>
        使用for循环：外层管趟数，内层管次数<br>
        （2）外层-趟数：arr.length-1<br>
        算法：长度就是 数组长度 减去 1<br>
        （3）里层-每行的交换次数：arr.length-i-1<br>
        算法：长度就是 数组长度 减去 次数,但次数是从0次开始的<br>
        （4）注意：声明一个空变量，内部交换2个变量的值 前一个和后一个数组元素相比较<br>
    </p>
    <h4>九、JS函数</h4>
    <p>
        （1）概念：在JS里，可能会定义非常多的相同代码或者功能相似的代码，这些代码大量重复使用<br>
        虽然for循环语句可以实现一些简单的重复操作，但是比较有局限性，此时就可以使用 JS函数<br>
        （2）函数：就是封装了一段 可被重复调用执行的 代码块 。通过此代码可以实现大量代码的重复使用<br>
        （3）封装：把一个或多个功能通过 函数的方式封装起来 ，对外提供一个简单的函数接口<br>
    </p>
    <p>
        1.函数的使用<br>
        使用分两步：声明函数、调用函数<br>
        （1）声明函数<br>
        语法：function 函数名(形参) {函数体代码;}<br>
        注意：<br>
        function 声明函数的关键字 全部小写<br>
        函数是做某件事情，函数名一般是动词<br>
        函数不调用 自己不执行<br>
        （2）调用函数<br>
        语法：函数名(实参);<br>
        注意：调用函数的时候不要忘记加小括号<br>
        口诀：函数不调用，自己不执行<br>
    </p>
    <p>
        2.函数的参数<br>
        可以利用函数的参数实现函数重复不同的代码<br>
        作用：在 函数内部 某些值不固定，可以通过参数在 调用函数时传递 不同的数值进去<br>
        两大类： 形参、实参<br>
        （1）形参<br>
        在声明函数的小括号里（形式上的参数）<br>
        形参类似于一个变量，形参是接收实参的<br>
        （2）实参<br>
        在函数调用的小括号里（实际的参数）<br>
        （3）注意：<br>
        函数的参数可以有 也可以没有 个数不限<br>
        多个参数之间用逗号隔开<br>
        （4）函数形参和实参匹配问题<br>
        如果实参的个数和形参的个数一致 则正常输出结果<br>
        如果实参的个数大于形参的个数 会取到形参的个数<br>
        如果实参的个数小于形参的个数 多余的形参定义为undefined 最终结果是NaN<br>
        建议 尽量让实参的个数与形参相匹配<br>
    </p>
    <p>
        3.函数的返回值<br>
        函数只是实现某种功能，最终结果需要返回给函数的调用者- 函数名() 通过 return 实现的<br>
        （1）语法：function 函数名(形参) { return 需要返回的结果;} 调用 函数名(实参);<br>
        （2）注意：<br>
        不要在内部写输出结果代码<br>
        只要函数遇到return 就把后面的结果返回给函数的调用者 函数名() = return后的的结果<br>
        实际开发中 我们经常用一个变量来接收 函数的返回结果 使用会更简单<br>
        （3）return终止函数：return 后面代码不会被执行<br>
        （4）return只会返回最后一个值<br>
        （5）函数没有return 则返回return最后的值，如果没有return 则返回undefined<br>
    </p>
    <p>
        5.break,continue,return的区别<br>
        （1）break：结束当前的循环体（只要针对于循环）<br>
        （2）continue：跳出本次循环，继续执行下次循环（只要针对于循环）<br>
        （3）return：不仅可以退出循环，还能返回return语句的值，同时还可以结束当前函数体内的代码（既针对循环，又针对函数）<br>
    </p>
    <p>
        6.arguments的使用<br>
        当不确定有几个参数传递的时候，可以用arguments来获取，在js中，它是当前函数的一个 内置对象。<br>
        所有的函数都内置了一个arguments对象，arguments对象中 储存了传递的所有实参。<br>
        arguments展示形式是一组 伪数组，但并不是真正意义的数组<br>
        （1）伪数组：<br>
        具有数组length属性<br>
        按照索引的方式进行存储的<br>
        它没有真正数组的一些方法 pop(),push()等等<br>
    </p>
    <p>
        7.函数可以调用另一个函数<br>
        因为每个函数都是独立的代码块，用于完成特殊任务，因此经常会用到函数相互调用的情况。<br>
    </p>
    <p>
        8.函数另一种声明方式<br>
        函数表达式（匿名函数）<br>
        （1）语法：var 变量名 = function () { };<br>
        （2）注意：<br>
        变量名，不是函数名<br>
        函数表达式声明方式跟声明变量差不多，只不过变量里面存的是指 而函数表达式里面存的函数<br>
        函数表达式也可以传递参数<br>
    </p>
    <h4>十、JS作用域</h4>
    <p>
        1.js作用域<br>
        就是代码名字（变量）在某个范围内起作用和效果<br>
        目的：为了提高程序可靠性，更重要的是减少命名冲突<br>
        js作用域(es6)之前：全局作用域 局部作用域<br>
        （1）全局作用域：整个script表现 或者是一个单独的js文件<br>
        （2）局部作用域（函数作用域）：在函数内部就是局部作用域 这个代码的名字只在函数内部起效果和作用<br>
        （3）在es6时候新增块级作用域,现阶段js中是没有块级作用域,在花括号里面的{}<br>
    </p>
    <p>
        2.变量作用域<br>
        根据作用域不同变量分为 全局变量 和 局部变量<br>
        （1）全局变量：在全局作用域下的变量 在全局下都可以使用<br>
        注意： 如果在函数内部 没有声明直接赋值的变量也属于全局变量<br>
        （2）局部变量：在局部作用域下的变量 或者在函数内部的变量 就是局部变量<br>
        注意： 函数的形参也可以看做是局部变量<br>
        （3）从执行效率来看全局变量和局部变量区别<br>
        全局变量:只有浏览器关闭的时候才会销毁 比较占内存<br>
        局部变量:当我们程序执行完毕就会销毁 比较节约内存资源<br>
    </p>
    <p>
        3.作用域链<br>
        内部函数访问外部函数的变量 采用的是链式查找的的方式来决定取哪个值，这种结构称为作用域链<br>
        就是 就近原则<br>
        有个概念：0级链、1级链、2级链...<br>
        口诀：站在目标出发，一层一层往外查找<br>
    </p>
    <h4>十一、JS预解析</h4>
    <p>
        JS代码是由浏览器中的js解析器来执行，js解析器在运行js代码时候分两步<br>
        ****预解析 和 代码执行****<br>
        （1）预解析：<br>
        js引擎会把js 里面所有的 var 还有 function 提升到当前作用域的最前面<br>
        变量预解析（变量提升）：就是把所有的变量声明提升到当前作用域最前面，不提升赋值操作<br>
        函数预解析（函数提升）：就是把所有函数声明提升到当前作用域最前面，不调用函数<br>
        （2）代码执行：<br>
        按照代码书写顺序从上往下执行<br>
    </p>
    <h4>十二、JS对象</h4>
    <p>
        分为三种：自定义对象、内置对象、浏览器对象<br>
        前两种对象是js基础内容，属于ECMAscript<br>
        第三种浏览器对象属于js独有，JS API用到<br>
    </p>
    <p>
        对象：必须是 一个具体事物 ，一个网页、一个数据库、一个远程服务器的连接等 都可以看做是“对象”<br>
        是由一组无序的相关 属性 和 方法 的集合 。例如字符串、数值、数组、函数等<br>
        （1）属性： 事物的特征，在对象中用 属性 来表示（常用名词）<br>
        （2）方法： 事物的行为，在对象中用 方法 来表示（常用动词）<br>
    </p>
    <h5>（一）自定义对象</h5>
    <p>
        1.创建对象三种方式(object)<br>
        （1）利用 字面量 创建对象<br>
        （2）利用 new Object创建对象<br>
        （3）利用 构造函数 创建对象<br>
    </p>
    <p>
        （1）利用 字面量 创建对象<br>
        对象字面量：就是花括号{}里面包含了表达这个具体事物（对象）的属性和方法<br>
        语法：var obj = {};<br>
        注意<br>
        里面的属性或者方法采取键值对的形式 键(属性名)： 值(属性值)<br>
        多个属性或者方法中间用逗号隔开的<br>
        方法冒号后面跟的是一个匿名函数<br>
        （2）使用对象：<br>
        要用对象的属性 我们采取 对象名.属性名 .理解为“的”<br>
        调用属性还有一种方法 对象名['属性名']<br>
        调用对象的方法 对象名.方法名();必须添加小括号<br>
    </p>
    <p>
        2.变量、属性，函数、方法的区别<br>
        （1）变量和属性相同点：都是用来存储数据的<br>
        不同点：<br>
        变量： 单独声明声明并赋值，使用时候直接写 变量名 。简话：单独存在<br>
        属性：在对象里面的，不需要声明的。使用时候必须是 对象.属性 或者 对象名['属性']<br>
        （2）函数和方法相同点：都是实现某种功能、做某件事<br>
        不同点：<br>
        函数：是单独声明,并且调用的, 函数名(); 。简话：单独存在<br>
        方法：在对象里面，调用的时候 对象.方法()<br>
    </p>
    <p>
        （2）利用 new Object创建对象<br>
        创建语法：var obj = new Object();<br>
        注意：<br>
        利用 等号 赋值的方法，添加对象的属性和方法<br>
        每个属性和方法之间用 分号结束<br>
        new Object中 首字母要大写<br>
    </p>
    <p>
        （3）利用 构造函数 创建对象<br>
        构造函数：就是把对象里面的一些相同属性和方法抽象出来封装到函数里面<br>
        解释：因为字面量对象、new Object对象 一次只能创建一个对象 里面很多属性、方法都是大量相同的<br>
        所以可以利用函数的方法重复这些相同的代码<br>
        但是构造函数不一样，里面封装的不是普通代码，而是对象。<br>
        语法：<br>
        function 构造函数名() { this.属性 = 值;this.方法 = function () {} };<br>
        调用时：<br>
        new 构造函数名();<br>
        注意：<br>
        构造函数名字首字母必须大写<br>
        构造函数不需要return 就可以返回结果<br>
        调用构造函数 必须使用 new<br>
        只要调用构造函数 就创建了一个对象 相当于 ={}<br>
        属性和方法必须添加this<br>
    </p>
    <p>
        3.构造函数和对象的区别<br>
        构造函数：泛指的某一大类(class) 抽象了对象的公共部分，封装到了函数里面<br>
        对象：是一个具体的事物，通过new关键字创建的<br>
        利用构造函数创建对象的过程 也称为对象的实例化<br>
    </p>
    <p>
        4.new关键字执行过程<br>
        （1）new构造函数可以再内存中创建一个空的对象<br>
        （2）this就会指向刚才创建的空对象<br>
        （3）执行构造函数里面的代码，给这个空对象添加属性和方法<br>
        （4）返回这个对象（所以构造函数里面不需要return）<br>
        记忆技巧：<br>
        （1）他俩生了一个宝宝<br>
        （2）这个宝宝必须是亲生的this指向<br>
        （3）教孩子度数一肚子墨水<br>
        （4）长大挣钱汇报父母<br>
    </p>
    <p>
        5.遍历对象<br>
        （1）语法：for...in 用于数组或者对象的属性进行循环操作<br>
        for (变量 in 对象) { }<br>
        （2）输出：<br>
        console.log(k); // k 变量 输出得到的是 属性名<br>
        console.log(obj[k]); // 得到的是里面的 属性值<br>
        （3）注意：<br>
        使用for...in 里面的变量 一般都会写 k 或者 key<br>
    </p>
    <h5>（二）内置对象</h5>
    <p>
        js语言自带的一些对象，这些对象供开发者使用，并提供一些常用的或者最基本而必要的功能（属性和方法）<br>
        最大优点就是帮助我们快速开发<br>
        js提供了多少个内置对象：Math、Date、Array、String等<br>
    </p>
    <p>
        1.查文档<br>
        （1）MDN：Mozilla开发者网络 提供了有关开发网络技术（open web）的信息，包括HTML、CSS、万维网、HTML5应用的API<br>
        官网：https://developer.mozilla.org/zh-CN/<br>
    </p>
    <p>
        2.Math 对象<br>
        （1）Math数学对象 不是一个构造函数，所以我们不需要new来调用，而是直接使用里面的属性和方法即可<br>
        （2）常用:<br>
        属性：Math.PI：圆周率<br>
        方法：<br>
        Math.floor()：向下取整 floor 地板 往最下了取值<br>
        Math.ceil()：向上取整 ceil 天花板 往最大了取值<br>
        Math.round()：四舍五入，就近取整，但是.5特殊，它往大了取 例如 -3.5 结果为-3<br>
        Math.abs()：绝对值<br> 隐式转换 会把字符串型 如'-1' 转换为数字型<br>
        Math.max()：最大值<br>
        Math.min()：最小值<br>

    </p>
    <p>
        3、Math.random() 随机数方法<br>
        （1）random()返回一个随机的小数<br>
        （2）一个浮点型伪随机数字，在0（包括0）和1（不包括）之间。<br>
        （3）这个方法里面不跟参数<br>
        （4）需要得到一个两数之间的随机整数，公式：<br>
        Math.floor(Math.random() * (max - min)) + min; //不含最大值，含最小值<br>
        （5）得到一个两数之间的随机整数，包括两个数在内，公式：<br>
        Math.floor(Math.random() * (max - min + 1)) + min; //含最大值，含最小值<br>
    </p>
    <p>
        4.Date 日期对象<br>
        是一个构造函数 必须使用new 来调用创建日期对象<br>
        （1）语法：var date = new Date();<br>
        （3）注意：<br>
        如果没有输入任何参数，返回当前系统的当前时间<br>
        如果括号内有时间，就返回参数里面的时间。例如 数字型 2019, 10, 01 或者是 字符串型 '2019-10-1 8:8:8'<br>
        （4）日期格式化<br>
        date.getFullYear()：获取当年<br>
        date.getMonth()：获取当月（0~11），返回的年份小一个月 记得月份 +1<br>
        date.getDate()：获取当天日期<br>
        date.getDay()：获取星期几（周日0到周六6）需要大写星期几，创建一个数组，索引第0个必须是星期日<br>
        date.getHours()：获取当前小时<br>
        date.getMinutes()：获取当前分钟<br>
        date.getSeconds()：获取当前秒钟<br>
        （5）获取日期的总的毫秒形式（时间戳）<br>
        Date对象是给予1970.1.1（世界标准时间）起的过了的总的毫秒数<br>
        我们经常利用总的毫秒数来计算时间，因为它更精确<br>
        第一种（最常用）：+new Date();<br>
        第二种：通过date.valueof() date.getTime()<br>
        第三种：H5新特性 不考虑兼容性 不需要new，直接Date.now() Date首字母必须大写，now后加小括号<br>
    </p>
    <h5>
        *****注意：<br>
        1.计算天数 公式：day = parseInt(总秒数/60/60/24)<br>
        2.计算小时 公式：hour = parseInt(总秒数/60/60%24)<br>
        3.计算分钟 公式：minute = parseInt(总秒数/60%60)<br>
        4.计算当前秒数 公式：second = parseInt(总秒数%60)<br>
    </h5>
    <p>
        5.Array 数组对象<br>
        （1）创建数组的两种方式：字面量方式、new Array();<br>
        （2）字面量方式：var arr = [1, 2, 3];<br>
        （3）利用new Array方式：var arr = new Array(2, 3);等价于[2,3] 这样写表示 里面有两个数组元素 是2和3<br>
        （4）注意：<br>
        第二种只写某一个数字型，表示数组的长度，里面有几个个空的数组元素 如：var arr = new Array(2); //这个2表示数组的长度为2 里面有两个空的数组元素<br>
    </p>
    <p>
        6.检测是否为数组<br>
        （1）instanceof:运算符 可以用来检测是否为数组 ture是、false否。如: (arr instanceof Array)<br>
        （2）Array.isArray(参数); ture是、false否。H5新增方法 ie9以上的<br>
        （3）注意：<br>
        Array.isArray 优先于 instanceof<br>
        Array.isAarray 俩A首字母一定要大写<br>
    </p>
    <p>
        7.添加删除数组元素的方法<br>
        添加的方法：<br>
        （1）arr.push(参数1,...)<br>
        说明：在数组末尾 添加一个或多个数组元素 push 后面往前推<br>
        注意：<br>
        push 可以给数组后面追加新的元素<br>
        push() 参数直接写数组元素就可以了<br>
        push完毕后 返回的结果是 新数组的长度<br>
        原数组也会发生变化<br>
        （2）arr.unshift(参数1,...)<br>
        说明：在数组的开头 添加一个或多个数组元素<br>
        注意：<br>
        unshift可以给数组前面追加新的元素<br>
        unshift() 参数直接写数组元素就可以了<br>
        unshift完毕后 返回的结果是 新数组的长度<br>
        原数组也会发生变化<br>
        删除的方法<br>
        （1）arr.pop()<br>
        说明：可以删除最后一个元素<br>
        注意：<br>
        pop 可以删除数组最后一个元素 记住一次只能删除一个元素<br>
        pop() 没有参数<br>
        pop完毕后 返回的结果是 删除的那个元素<br>
        原数组也会发生变化<br>
        （2）arr.shift()<br>
        说明：可以删除第一个元素<br>
        注意：<br>
        shift 可以删除数组第一个元素 记住一次只能删除一个元素<br>
        shift() 没有参数<br>
        shift完毕后 返回的结果是 删除的那个元素<br>
        原数组也会发生变化<br>
    </p>
    <p>
        8.数组排序<br>
        （1）翻转数组：arr.reverse();<br>
        （2）数组升、降序方法：<br>
        arr.sort(function (a, b) {<br>
        return a - b; // 按照升序的顺序<br>
        return b - a; // 按照降序的顺序<br>
        });<br>
    </p>
    <p>
        9.数组索引<br>
        作用就是查找后返回该数组元素的索引号<br>
        （1）arr.indexOf(数组元素)<br>
        它按 从前往后 只返回 遇到第一个 满足条件的索引号<br>
        如果在该数组里找不到元素，则返回-1<br>
        （2）lastIndexOf(数组元素)<br>
        它按 从后往前 只返回 遇到第一个 满足条件的索引号<br>
        如果在该数组里找不到元素，则返回-1<br>
    </p>
    <p>
        10.数组转换字符串<br>
        （1）arr.toString()<br>
        默认逗号分隔<br>
        （2）arr.join('分隔符')<br>
        不填默认，分隔<br>
        填写就是按输入的分隔符来分隔 一般用&来上传表单内容<br>
    </p>
    <p>
        11.连接数组<br>
        （1）''.concat(...arr)：连接合并一个数组内的数组元素<br>
        注意:此''代表空值用于''连接.concat(...arr)<br>
        如：var arr = ['hello', 'web'];<br>
        console.log(''.concat(...arr)); // helloweb<br>
        （2）arr.concat('','','')：连接合并两个或多个数组元素<br>
        如：var arr = '1';<br>
        console.log(arr.concat('2', '3')); // 123<br>
        (3) arr.concat(arr1，[]):连接合并两个或多个数组,并返回合并到一起的新数组<br>
        如:var arr = [1,2];<br>
        var arr1 = [3,4];<br>
        console.log(arr2.concat(arr1, [5])); // [1,2,3,4,5]<br>
    </p>
    <p>
        12.截取数组<br>
        （1）arr.slice(begin,end)); 索引号从0开始<br>
        注意：包括 begin，不包括end,生成新数组，原数组不变。<br>
        （2）输入一个索引号，则截取从这个索引号之后的所有数生成新数组<br>
        如：var arr = [1, 2, 3, 4, 5];<br>
        console.log(arr.slice(2)); // [3,4,5]<br>
        （2）输入连个个索引号，则从第一个索引号之后到最后一个索引号(不含最后一个索引号)的所有数生成新数组<br>
        如：console.log(arr.slice(1, 5)); // [2,3,4,5]<br>
    </p>
    <p>
        13.添加删除元素<br>
        arr.splice(索引号起始位, 需删除几个，添加或替换的元素1，添加或替换的元素1，....)<br>
        如：var arr = [1, 2, 3, 4, 5];<br>
        arr.splice(4, 1, 6, 7);<br>
        console.log(arr); // [1,2,3,4,6,7]<br>
    </p>
    <p>
        14.基本包装类型<br>
        为了方便操作基本数据类型，js提供了三个特殊的引用类型：String、Number、Boolean<br>
        就是把简单数据类型包装成为了复杂数据类型的过程<br>
        （1）先把简单数据类型包装成复杂数据类型<br>
        （2）把临时变量的值给声明变量<br>
        （3）销毁这个临时变量<br>
    </p>
    <p>
        16.字符串不可变性<br>
        指的是里面的值不可变，虽然看上去改变内容，但其实是地址变了，内存中新开辟了一个内存空间<br>
        因为字符串的不可变性，所以不要大量的拼接字符串<br>
    </p>
    <p>
        17.根据字符返回位置<br>
        字符串所有的方法，都不会修改字符串本身(字符串不可变性)，操作完会返回一个新的字符串<br>
        str.indexOf('要查找的字符',[起始的位置])<br>
        从索引号是[起始的位置]的位置开始往后查找<br>
    </p>
    <p>
        18.（重点）根据位置返回字符<br>
        （1）根据索引号位置返回字符<br>
        语法：str.charAt(索引号);<br>
        （2）H5新增特性-根据索引号位置返回字符<br>
        语法：str[index]；<br>
        （3） 返回相应索引号的字符ASCII值<br>
        目的：判断用户按下了哪个键<br>
        语法：str.charCodeAt(索引号);<br>
    </p>
    <p>
        19.判断是否有该属性<br>
        语法：对象名['属性名'];<br>
    </p>
    <p>
        20.（重点）字符操作方法<br>
        （1）拼接<br>
        str.concat(str1,str2,str3,...)；<br>
        等效与用"+"来拼接，加号更常用<br>
        （2）截取<br>
        str.substr('截取的起始位置索引号','截取几个字符')<br>
        （3）替换字符<br>
        str.replace('被替换的字符','替换为的字符')<br>
        只会替换第一个字符<br>
        实际开发中利用for循环过滤掉文章中的敏感字变为*<br>
        （4）字符转换为数组<br>
        str.split('分隔符')<br>
        看数组元素用什么分隔符链接的<br>
        如：var str5 = 'red&pink&blue'<br>
        console.log(str5.split('&')) // ["red", "pink", "blue"]<br>
    </p>
    <p>
        21.转换大小写<br>
        （1）str.toUpperCase() 转换为大写<br>
        （2）str.toLowerCase() 转换为小写<br>
    </p>
    <h4>十三、JS简单类型与复杂类型</h4>
    <p>
        1.简单类型与复杂类型<br>
        简单类型又称基本数据类型或者 值类型；<br>
        复杂数据类型又称 引用类型。<br>
        （1）值类型<br>
        在储存变量中储存的是值本身，如：String、Number、Boolean、Undefined、Null五大类<br>
        注意：null 返回的是一个空的对象 object<br>
        如果有个变量我们以后打算存储为对象，暂时没想好防晒帽，这时候就给null<br>
        （2）引用类型<br>
        在储存时变量中储存的仅仅是地址（引用），通过new关键字创建的对象（系统对象、自定义对象），如Object、Array、Date等<br>
    </p>
    <p>
        2.堆栈空间分配区别<br>
        （1）栈（操作系统）：<br>
        简单数据类型存放到栈里面：<br>
        由操作系统自动分配释放存放函数的参数值、局部变量的值等，其操作方式类似于数据结构中的栈；<br>
        （2）堆（操作系统）：<br>
        复杂数据类型存放到堆里面：<br>
        储存复杂类型（对象），一般由程序员分配释放，若程序员不释放，由垃圾回收机制回收<br>
        （3）注意：js中没有堆、栈的概念，只是更方便理解代码一些执行方式<br>
    </p>
    <p>
        3.内存分配<br>
        （1）简单数据类型的：是存放在栈里面 里面开辟一个空间存放的是值<br>
        （2）复杂数据类型：首先在里面存放一个地址（十六进制表示，系统自动分配的），<br>
        然后这个地址指向 堆 里面的数据<br>
    </p>
    <p>
        4.数据类型传参<br>
        （1）简单类型传参：<br>
        函数的形参也可以看做是一个变量，当我们把一个值类型变量作为参数传给函数的形参时，<br>
        其实是把变量在栈空间里的值复制了一份给形参，那么方法内部对形参做任何更改，都不会影响到外部变量<br>
        （2）复杂类型传参：<br>
        函数的形参也可以看做是一个变量，当我们把引用类型变量传给形参时，
        其实是把变量在栈内空间里保存的堆地址复制给了形参，形参和实参其实保存的是同一个地址，所以错做的是同一个对象<br>
    </p>
    <h4>十四、Web APIs</h4>
    <p>
        1.web APIs和JS基础关联性<br>
        Js组成：ECMAScript、DOM、BOM<br>
        （1）JS基础语法=ECMAScript<br>
        标准规定的基本语法<br>
        掌握js基础语法<br>
        做不了网页交互效果<br>
        （2）web APIs=BOM,DOM<br>
        是W3C组织的标准<br>
        主要学习DOM和BOM<br>
        JS所独有的部分<br>
        学习页面交互功能<br>
    </p>
    <p>
        2.API和web API<br>
        （1）API:应用程序编程接口，是给程序员提供的一种工具，以便能更轻松的实现想要完成的功能<br>
        （2）WEB API:是浏览器提供的一套操作 浏览器功能 和 页面元素 的API（BOM和DOM），主要针对浏览器做交互效果<br>
        一般都有输入和输出（函数的传参和返回值），有很多的方法（函数）<br>
        （3）web APIs:因为web API，所以将js主要做交互效果阶段称为web APIs<br>
    </p>
    <h5>DOM 文档对象模型</h5>
    <p>
        是W3C组织推荐的处理可扩展标记语言的标准 编程接口<br>
        W3C已经定义了一系列的DOM接口，通过这些DOM接口可以改变网页的内容、结构、样式<br>
    </p>
    <p>
        2.DOM树
        （1）文档：一个页面就是一个文档，DOM中使用 document 表示。<br>
        （2）元素：页面中的所有变迁都是元素，DOM中使用 element 表示。<br>
        （3）节点：网页中所有的内容都是节点（标签节点、属性节点、文本节点、注释节点等等），DOM中使用 node 来表示。<br>
        （4）DOM把以上内容都可以看做是对象<br>
    </p>
    <p>
        3.获取元素<br>
        （1）根据ID获取<br>
        语法：document.getElementById('大小写敏感的字符串')；获取带有ID的元素对象。<br>
        因为文档页面从上往下加载，所以现要有标签，所以script写到标签的下面<br>
        get 获得 Element 元素 By通过 驼峰命名法<br>
        参数 id是大小写敏感的字符串 ('')<br>
        返回的是一个元素对象<br>
        （1.1）console.dir 打印返回的元素对象 更好的查看里面的属性和方法<br>
        （2）根据标签名获取<br>
        语法：document.getElementsTagName('标签名'); 返回带有指定标签名的 对象的集合<br>
        返回的是 获取过来元素对象的集合 以伪数组的形式存储的<br>
        依次打印里面的元素对象 可以采用遍历的方式<br>
        得到的元素对象是动态的<br>
        如果页面中只有一个子元素标签 返回的环视伪数组的形式<br>
        如果页面中没有这个元素 返回的是个空的伪数组 []<br>
        （2.1）element.getElementsByTagName('标签名')；获取某个元素（父元素）内部的所有指定标签名的子元素<br>
        父元素必须是单个对象（必须指明是哪一个元素对象），获取的时候不包括父元素自己<br>
        （3）通过HTML5新增方法获取<br>
        语法：document.getElementByClassName('类名')；根据类名获得某些元素集合<br>
        （3.1）语法：document.querySelector('./#选择器')；根据指定选择器返回第一个元素对象<br>
        （3.2）语法：document.querySelectorAll('./#选择器')；根据指定选择器的所有元素对象集合<br>
        切记：querySelector/All，里面的选择器要加符号 类选择加. id选择器加# 子标签不用加<br>
        （4）获取特殊元素（body和html）<br>
        语法：document.body; 获取body 元素对象<br>
        语法：document.documentElement; 获取html 元素对象<br>
    </p>
    <p>
        4.事件基础-事件三要素<br>
        （1）事件概述：js使我们有能力创建动态页面，而事件是可以被js检测到的行为。简单理解：触发---相应机制<br>
        （2）事件三要素（事件三个组成部分）：事件源、事件类型、事件处理程序<br>
        事件源：事件被触发的对象---“谁”<br>
        事件类型：如何触发，什么事件。比如鼠标点击触发（onclick） 还是鼠标经过（onMouseOver） 还是键盘按下等等<br>
        事件处理程序：通过一个函数赋值的方式完成<br>
        例如：<br>
        var btn = document.getElementById('btn');<br>
        btn.onclick = function () {<br>
        alert('点钮弹窗');<br>
        （3）执行事件的步骤<br>
        获取事件源<br>
        注册事件（绑定事件）<br>
        添加事件处理程序（采用函数赋值形式）<br>
        }<br>
    </p>
    <h4>常见鼠标事件</h4>
    <h5>
        （1）onclick：鼠标点击<br>
        （2）onmouseover：鼠标经过<br>
        （3）onmouseout：鼠标离开<br>
        （4）onfocus：获得鼠标焦点<br>
        （5）onblur：失去鼠标焦点<br>
        （6）onmousemove：鼠标移动<br>
        （7）onmouseup：鼠标弹起<br>
        （8）onmousedown：鼠标按下<br>
    </h5>
    <p>
        5.操作元素<br>
        可以利用DOM操作元素来改变元素里面的内容、属性等。<br>
        注意以下都是属性：<br>
        （1）改变元素内容<br>
        语法：element.innerText<br>
        完全显示从起始位置到终止位置的内容<br>
        不识别HTML标签，标签会直接显示，非标准，去除空格和换行<br>
        语法：element.innerHTML(HTML要大写) （经常使用）<br>
        完全显示从起始位置到终止位置的全部内容<br>
        识别HTML标签，W3C推荐标准，保留空格和换行的<br>
        这两个属性时可读写的 可以获取元素里面的内容<br>
        （2）其他常用元素的属性操作<br>
        src、href、id、alt、title等<br>
    </p>
    <p>
        6.表单元素的属性操作<br>
        .type、.value、.checked、.selected、.disabled(禁用 =true)<br>
        注意：this 指向的时间函数的调用者<br>
    </p>
    <p>
        7.样式属性操作<br>
        可以通过js修改元素的大小、颜色、位置等样式<br>
        （1）element.style.修改的属性（驼峰命名法）：行内样式操作<br>
        特点：样式比较少或者功能简单的情况下使用<br>
        （2）element.className='调用CSS中预先写好的样式'：类名样式操作<br>
        可以通过 修改className更改元素的样式， 适合于样式较多或者功能复杂的情况<br>
        会直接更改元素的类名，会覆盖掉原先的类名<br>
        如果想保留原先的类名可以把原来的类名写进去(多类名选择器)<br>
    </p>
    <p>
        8.排他思想（算法）<br>
        如果有同一组元素，我们想要某一个元素实现某种样式，需要用到循环的排他思想算法：<br>
        （1）所有元素全部清除样式（干掉其他人）；<br>
        （2）给当前元素设置样式（留下自己）<br>
        （3）顺序不能颠倒<br>
    </p>
    <p>
        9.自定义属性的操作<br>
        （1）获得属性值<br>
        element.属性;：获取属性值<br>
        获取内置属性值（元素本身自带的属性）<br>
        element.getAttribute('属性');<br>
        主要获得自定义的属性（标准方法），程序员自定义的属性<br>
        （2）设置属性值<br>
        element.属性='值';：设置内置属性值<br>
        设置内助属性值<br>
        element.setAttribute('属性','值')；<br>
        主要设置自定义的属性（标准方式）<br>
        注意：class 特殊 写的就是class 不是className<br>
        （3）移除属性<br>
        element.removeAttribute('属性');<br>
    </p>
    <p>
        10.H5自定义属性<br>
        自定义属性目的：为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中<br>
        自定义属性获取是通过getAttribute('属性')获取<br>
        但是有些自定义属性很容易引起歧义，不容易判断是元素的内置属性还是自定义属性<br>
        （1） H5规定自定义属性data-开头做为属性名并且赋值<br>
        如：data-属性="值"<br>
        使用JS设置<br>
        element.setAttribute('data-属性',值);<br>
        （2）获取H5自定义属性（有兼容问题，IE11y以上才支持） 只能获取 data-开头的<br>
        dataset 是一个集合 里面存放了所有以data开头的自定义属性<br>
        兼容性获取：element.getAttribute('data-属性');<br>
        H5新增element.dataset.属性或者element.dataset['属性']<br>
        如果自定义属性里面有多个-链接的单词，获取的时候采取 驼峰命名法<br>
    </p>
    <p>
        11.节点操作<br>
        （1）利用节点层级关系获取元素<br>
        利用父、子、兄节点关系获取元素<br>
        逻辑性强，但是兼容性稍差<br>
        节点使用node来表示<br>
        一般来说，节点至少拥有nodeType（节点类型）、nodeName（节点名称）、nodeValue（节点值）这三个基本属性<br>
        （2）注意：<br>
        元素节点nodeType为1<br>
        属性节点nodeType为2<br>
        文本节点nodeType为3(文本节点包含文字、空格、换行等)<br>
        实际开发中，节点操作主要操作的是元素节点<br>
    </p>
    <p>
        12.节点层级<br>
        常见的是 父、子、兄层级关系<br>
        （1）父级节点<br>
        node.parentNode<br>
        得到的是 离元素最近的父级节点(亲爸爸) 如果找不到父节点 返回为null<br>
        *（2）子级节点<br>
        parentNode.children(非标准)（重点掌握这个子节点）<br>
        是一个只读属性，返回所有的子元素节点。它只返回子元素节点，其余节点不返回<br>
        虽然children是一个非标准的，但是得到了各个浏览器支持，放心使用<br>
        （3）子级节点：parentNode.childNodes(标准)<br>
        返回包含指定节点的子节点集合，该集合为及时更新的集合<br>
        注意：<br>
        得到所有的子节点 包含 元素节点 文本节点等等<br>
        如果只想获得里面的元素节点，则需要专门处理。所以我们一般不提倡使用childNodes<br>
        （4）获取第一个子元素和最后一个子元素<br>
        frist/lastchlid 第一个子节点 不管是文本节点还是元素节点<br>
        frist/lastelementchild 返回第一个子元素节点<br>
        以上两种方法有兼容问题，IE9以上才支持<br>
        *实际开发的写法，既没有兼容性问题又返回第一个子元素,如下：<br>
        获取首个子元素节点：parentNode.children[0];<br>
        获取最后一个子元素节点：parentNode.children[parentNode.children.length - 1];<br>
        （5）兄弟节点<br>
        node.Sibling<br>
        返回当前元素的下一个兄弟节点，找不到返回null，同样，也是包含所有的节点<br>
        node.previousSibling<br>
        返回当前元素的上一个兄弟节点，找不到返回null，同样，也是包含所有的节点<br>
        *node.nextElementSiling<br>
        返回当前元素的下一个兄弟元素节点，找不到返回null<br>
        *node.previousElementSibling<br>
        返回当前元素的上一个兄弟元素节点，找不到返回null<br>
        以上两种标*方法有兼容性问题，IE9以上才支持<br>
    </p>
    <p>
        13.创建和添加节点-元素节点<br>
        想要页面添加一个新的元素：1.创建元素 2.添加元素<br>
        （1）创建节点<br>
        document.createElement('tagName');<br>
        方法创建由tagName指定的HTML元素。<br>
        因为这些元素原先不存在，是根据我们需求动态生成的，所以我们也称作 动态创建元素节点<br>
        （2）添加节点<br>
        node.appendChlid(child);<br>
        node是父级 child是子级<br>
        方法将一个节点添加到指定父级节点的子节点列表 末尾。类似于CSS中的after伪元素<br>
        node.insertBefore(child,指定元素);<br>
        方法将一个节点添加到指定父级节点的子节点列表 前面。类似于CSS中的before伪元素<br>
    </p>
    <p>
        14.删除节点<br>
        node.removeChild(child);<br>
        从DOM中删除一个子节点，返回删除的节点<br>
    </p>
    <p>
        15.复制节点（克隆节点）<br>
        node.cloneNode();<br>
        方法返回调用该方法的节点的一个副本。也称克隆节点/拷贝节点<br>
        注意：
        如果括号参数为 空或者false ，则 浅拷贝，只复制标签，不复制内容<br>
        如果括号参数为true，则 深拷贝，复制标签，也复制内容<br>
    </p>
    <p>
        16.三种动态创建元素区别<br>
        （1）document.write()（了解，实际开发很少用）<br>
        直接将内容写入页面的内容流，但是文档执行完毕，则它会导致页面全部重绘<br>
        （2）document.innerHTML()<br>
        将内容写入某个DOM节点，不会导致页面全部重绘<br>
        创建多个元素效率更高（不要拼接字符串，采用数组形式拼接），结构稍微复杂<br>
        （3）document.createElement()<br>
        创建多个元素效率低一些，但是结构更清晰<br>
        （4）总结：<br>
        不同浏览器下，innerHTML 效率要比 createElement 高<br>
    </p>
    <h5>DOM-事件高级</h5>
    <p>
        1.注册事件（绑定事件）br>
        给元素添加事件，称为 注册事件 或者 绑定事件<br>
        两种方式：传统方法、方法监听注册方式<br>
        （1）传统注册方式<br>
        利用on开头的事件，如onclick<br>
        行内添加 button onclick="alert('hi')" /button<br>
        添加函数 btn.onclick=function(){};<br>
        特点：注册事件的唯一性<br>
        同一个元素同一个事件只能设置一个处理函数，最后注册的处理函数会覆盖当前注册的处理函数<br>
        （2）方法监听注册方式<br>
        W3C标准 推荐方式<br>
        特点：同一个元素同一个事件可以注册多个监听器<br>
        按照注册的顺序依次执行<br>
        eventTarget.addEventListener(type,listener['',useCapture]);<br>
        它是一个方法,IE9之前不支持，可使用attachEvent()代替<br>
        将指定的监听器注册到eventTarget（目标对象）上，当该对象触发指定的事件时，就会执行事件处理函数<br>
        参数解释：<br>
        'type'：事件类型字符串，比如:'click'、'Mouseover',必定加引号'',而且不带on<br>
        listener：事件处理函数，事件发生时，会调用该监听函数<br>
        useCapture：可选参数，是一个布尔值，默认是false<br>
        （3）attachEvent()（了解）<br>
        该特性非标准，尽量不要生产环境中使用，只有IE浏览器可以使用此效果<br>
        eventTarget.attachEvent('eventNameWithOn',callback)<br>
        将指定监听器注册到eventTarget（目标对象）上，当该对象触发指定的事件时，指定的回调函数就会被执行<br>
        参数解释：<br>
        'eventNameWithOn'：事件类型字符串，比如onclick、onmousemove，必定加引号'',这里要带on<br>
        callback：事件处理函数，当目标触发事件时回调函数被调用<br>
    </p>
    <p>
        2.删除事件（解绑事件）<br>
        （1）传统方式<br>
        eventTarget.onclick=null;<br>
        （2）方法监听注册方式<br>
        eventTarget.removeEventListener('type',调用的函数名[,useCapture]);<br>
        eventTarget.datachEvent('enevtNameWithOn',调用的函数名);老版本attachEvent<br>
        以上(2)内两种方法都 需要先需要在外面建函数，然后里面函数调用，不需要加()调用<br>
    </p>
    <p>
        3.DOM事件流<br>
        事件流 描述的是从页面中接收事件的顺序<br>
        事件 发生时会在元素节点之间按照特定 的 顺序传播，这个 传播过程 既 DOM事件流<br>
        DOM事件流分为3个阶段：捕获阶段、当前目标阶段、冒泡阶段<br>
        事件捕获：网景最早提出，由DOM最顶层节点开始，然后逐级向下传播到最具体的元素接收的过程<br>
        事件冒泡：IE最早提出，事件开始时由最具体的元素接收，然后逐级向上传播到到DOM最顶层节点的过程<br>
        注意：<br>
        JS代码中只能执行捕获或者冒泡其中一个阶段<br>
        onclick和attachEvent(ie)只能得到冒泡阶段<br>
        捕获阶段 如果addEventListener 第三个参数是true，则处于捕获阶段 document->html->body->father->son<br>
        冒泡阶段 如果addEventListener 第三个参数是false或者省略，则处于捕获阶段 son->father->body->html->document<br>
        实际开发中很少使用捕获事件，更关注冒泡事件<br>
        有些事件是没有冒泡的，比如：onblur、onfocus、onmouseenter、onmouseleave<br>
    </p>
    <p>
        4.事件对象（重点）<br>
        (1)event 就是一个事件对象，写到我们监听函数的 小括号内 当形参来看<br>
        (2)事件对象只有有了事件才会存在，它是系统给我们自动创建的，不需要我们传递参数<br>
        (3)事件对象是我们事件的一些列相关数据的集合 跟事件相关，<br>
        比如鼠标点击里面就包含了鼠标点击的相关信息，鼠标坐标等等，<br>
        如果键盘事件里面就包含了键盘事件的信息，比如判断用户按下了哪个键等等<br>
        (4)这个事件对象可以自己命名，比如event、evt、都可以<br>
        (5)事件对象也有兼容性问题，IE678 通过window.event 兼容性写法 e = e || window.event<br>
    </p>
    <p>
        5.事件对象属性和方法<br>
        *（1）e.target：返回 触发 时间的对象（标准方法）<br>
        e.target 返回的是 触发事件 的对象（元素）；this 返回的是 绑定事件 的对象（元素）<br>
        区别：e.target点击了哪个元素 就返回哪个元素；this哪个元素绑定了这个点击事件 就返回谁<br>
        跟this有个非常相似的属性，currentTarget IE678不认识（了解即可）<br>
        （2）e.srcElement：返回 触发 时间的对象（非标准方法）<br>
        *（3）e.type：返回事件的类型，如：click、mouseover等 不带on<br>
        *（4）e.preventDefault()：该属性阻止默认事件（默认行为） 标准方式 如：不让链接跳转等<br>
        （5）e.returnValue：该属性阻止默认事件（默认行为） 非标准 IE678使用 如：不让链接跳转等<br>
        *（6）e.stopPropagation()：阻止冒泡 标准方式<br>
        （7）e.cancelBubble = true：该属性阻止冒泡 非标准 IE678使用<br>
    </p>
    <p>
        6.事件委托（代理、委派）<br>
        事件冒泡本身的特性，会带来坏处，也会 带来好处 需要灵活掌握<br>
        原理：不是给每一个子节点单独设置事件监听器，而是设置在父节点上，然后利用冒泡原理影响设置每个子节点<br>
        作用：只操作了一次DOM,提高了程序的性能<br>
    </p>
    <p>
        7.禁止选中文字和禁止右键菜单<br>
        （1）禁止鼠标右键<br>
        contextmenu：主要控制应该何时显示右键上下文菜单，主要用于程序员取消默认的右键上下文菜单<br>
        （2）禁止鼠标选中<br>
        selectstart：开始选中<br>
    </p>
    <p>
        8.鼠标事件对象<br>
        event对象代表事件的状态，跟事件相关的一些列信息的集合。<br>
        现阶段学习：鼠标事件对象MouseEvent 和 键盘事件对象KeyboardEvent<br>
        （1）e.clientX/Y 鼠标在 浏览器可视区域 的X和Y坐标<br>
        （2）e.pageX/Y 鼠标在 页面文档 的X和Y坐标<br>
        （3）e.screenX/Y 返回鼠标相对于 电脑屏幕 的X和Y坐标<br>
    </p>
    <p>
        9.常用键盘事件<br>
        （1）onkeyup：某个按键被松开时触发<br>
        （2）onkeydown：某个按键被按下时触发<br>
        （3）onkeypress：某个按键被按下时触发（但不识别功能键，如ctrl、shift、箭头等）<br>
        三个事件的执行顺序 keydown->keypress->keyup<br>
    </p>
    <p>
        10.键盘事件对象<br>
        （1）判断用户按下哪个键<br>
        keyCode:可以得到相应键的ASCII码值<br>
        注意：<br>
        keyup 和 keydown 事件 不区分字母大小写 如：a和A ASCII码值都是65<br>
        keypress 事件是 区分字母大小写<br>
    </p>
    <h5>BOM 浏览器对象模型</h5>
    <p>
        BOM最初是Netscape(网景)浏览器标准的一部分，JS语法标准化组织是ECMAA，DOM标准化组织是W3C<br>
        它提供了独立于内容而与 浏览器窗口进行交换的对象，其核心对象是 window<br>
        BOM由一些列的对象构成，并且每个对象都提供了很多方法和属性<br>
        BOM缺乏标准，是浏览器厂商各自定义的，兼容性较差<br>
        BOM比DOM更大，包含了DOM<br>
    </p>
    <p>
        1.BOM构成<br>
        window对象是浏览器的顶级对象，她有双重角色<br>
        它是JS访问浏览器的一个接口，如改变浏览器大小、滚动页面、刷新页面等等<br>
        它是一个全局对象。定义在全局作用域中的变量、函数都会变成window对象的属性和方法<br>
        在调用的时候可以省略window，弹出的对话框是属于window对象方法<br>
        特殊属性 window.name，name是关键字，因此不要用直接用name来命名各种<br>
    </p>
    <p>
        2.window对象的常用事件<br>
        (1)页面加载事件<br>
        window.onload：窗口（页面）加载事件<br>
        当文档内容完全加载完成会触发该事件（包括图像、脚本文件、CSS文件等），就调用的处理函数<br>
        注意：<br>
        用window.onload就可以把js代码写到页面元素的任意地方，onload是等页面全部加载完毕，再去执行处理函数<br>
        window.onload传统注册事件方式只能写一次，如果有多个，会以最后一个window.onload为准<br>
        如果使用addEventListener没有限制<br>
        DPMContentLoaded：仅当DOM加载完成，不包括样式表、图片、flash等等 IE9+以上才支持<br>
        如果页面图片很多的话，从用户访问到onload触发可能需要较长事件，交互效果就不能实现，必然影响用户体验，此时用DOMContentLoaded事件比较合适<br>
    </p>
    <p>
        （2）调整窗口大小事件<br>
        window.onresize<br>
        调整窗口大小加载事件，当触发时就调用的处理函数<br>
        注意：<br>
        只有窗口大小发生像素变化，就会触发这个事件<br>
        经常利用这个事件完成响应式布局。window.innerWidth当前屏幕的宽度<br>
    </p>
    <p>
        3.定时器<br>
        两种定时器：setTimeout()、setInterval()<br>
        （1）区别：
        setTimeout 延迟时间到了，就去调用这个回调函数，只调用一次，就结束了这个定时器<br>
        setInterval 每隔这个延迟时间，就去调用这个回调函数，会调用很多次，重复调用这个函数<br>
        （2）相同点：<br>
        这个window在调用时可以省略<br>
        这个函数可以直接写函数，还可以写 函数名 ，还有一种不提倡的写法'函数名()'<br>
        这个延时时间单位是毫秒，但是可以省略，如果省略默认是0<br>
        页面中可能有很多的定时器，经常给定时器加标志符（名字）<br>
    </p>
    <p>
        （1）window.setTimeout(调用函数,延迟的毫秒数);<br>
        setTimeout()用于设置一个定时器，该定时器在定时器到期后执行调用函数<br>
        （2）也称回调函数 callback，简单理解：上件事干完，再回头调用这个函数<br>
        （3）停止setTimeout()定时器<br>
        window.clearTimeout(timeoutID);<br>
        clearTimeout()取消之前通过setTimeout建立的定时器<br>
        注意：<br>
        window可以省略<br>
        里面的参数就是定时器的标识符（名字）<br>
    </p>
    <p>
        （1）window.setInterval(回调函数,间隔的毫秒数);<br>
        setInterval()重复调用一个函数，每个设置的时间，就去调用一次回调函数<br>
        （2）停止setInterval()定时器<br>
        window.clearInterval(intervalID);<br>
        clearInterval()取消之前通过setInterval建立的定时器<br>
        注意：<br>
        window可以省略<br>
        里面的参数就是定时器的标识符（名字）<br>
    </p>
    <p>
        （1）this<br>
        指在函数定义的时候是确定不了的，只有函数执行的时候才能确定this到底指向谁<br>
        一般情况下this最终指向的是那个调用它的对象<br>
        注意：<br>
        全局作用域或者普通函数中this指向全局对象window（注意定时器里面this指向window）<br>
        方法调用中谁调用this指向的声明的对象<br>
        构造函数中 this 指向构造函数的实例对象<br>
    </p>
    <p>
        4.JS执行队列<br>
        （1）JS是单线程<br>
        JS语言一大特点就是 单线程，也就是说，同一时间只能做一件事<br>
        单线程就意味着，所有任务需要排队，前一个任务结束，才会执行后一个任务<br>
        （2）核心：
        先执行 执行栈中的同步任务<br>
        异步任务（回调函数）放入任务队列中<br>
        一旦执行栈中的所有同步任务执行完毕，系统就会按次序读取任务队列中的异步任务，于是被读写的异步任务结束等待状态，进入执行栈，开始执行<br>
        （3）事件循环：由于主线程不断的重复获得任务、执行任务、再获取任务、执行任务，所以这种机制被称为事件循环（event loop）<br>
    </p>
    <p>
        （2）同步和异步<br>
        为解决单线程问题，H5提出了web worker标准，允许JS脚本创建多个线程。出现了同步和异步<br>
        本质区别：这条流水线上各个流程的执行顺序不同<br>
        同步任务：都在主线程上执行，形成一个 执行栈<br>
        异步任务：JS异步是通过回调函数实现的<br>
        一般来说，异步任务有三种类型：<br>
        普通事件，如click、resize等<br>
        资源加载：如load、error等<br>
        定时器：包括setInterval、setTimeout等<br>
        异步任务相关回调函数添加到任务队列中（任务队列也称为了消息队列）<br>
    </p>
    <p>
        5.location对象<br>
        （1）location属性用于 获取或设置窗体的URL，并且可以用于 解析URL，这个属性返回的是一个对象<br>
        属性：<br>
        *location.href：获取或者设置整个URL<br>
        location.host：返回主机（域名）<br>
        location.port：返回端口号<br>
        location.pathname：返回路径<br>
        *location.search：返回参数<br>
        location.hash：返回片段 #后面内容 常见于链接 锚点<br>
        （2）URL：统一资源定位符，是互联网上标准资源的地址，互联网上每个文件都有一个唯一的URL<br>
        URL的一般语法格式：<br>
        protocol://host[:port]/path/[?query]#fragment<br>
        protocol：通信协议 常用的http、ftp、maito等<br>
        host：主机（域名）<br>
        port：端口号 可选，省略时使用方案的默认端口 如http的默认端口为80<br>
        path：路径 由零或多个/符号隔开的字符串，一般用来表示主机上的一个目录或者文件地址<br>
        query：参数 以键值对的形式，通过&符号分隔开<br>
        fragment：片段 #后面内容 常见于链接 锚点<br>
        （3）location对象的方法<br>
        location.assign()：<br>
        跟href一样，可以跳转页面（也称为重定向页面）<br>
        记录浏览历史，可以实现后退功能<br>
        location.replace()：<br>
        替换当前页面，因为不记录历史，所以不能后退页面<br>
        location.reload(true)：重新加载页面，相当于刷新按钮或者F5，如果参数为true强制刷新Ctrl+F5<br>
    </p>
    <p>
        6.navigator对象<br>
        包含有关浏览器的信息，有很多属性，最常用的是userAgent，该属性可以返回由客户机发送服务器的user-agent头部的值<br>
        代码可以判断用户哪个终端打开页面，实现跳转<br>
    </p>
    <p>
        7.history对象<br>
        与浏览器历史记录进行交互。该对象包含用户（在浏览器窗口中）访问过的URL<br>
        back()：可以后退功能<br>
        forward()：前进功能<br>
        go(参数)：前进后退功能 参数如果是1前进一个页面；如果是-1后退一个页面<br>
    </p>
    <h4>十五、PC端网页特效</h4>
    <h5>1.元素偏移量offset系列</h5>
    <p>
        offset系列相关属性可以 动态的 得到该元素的位置（偏移）、大小等<br>
        （1）获取元素距离带有定位父元素的位置<br>
        （2）获得元素自身的代销（高/宽）<br>
        （3）注意：返回的值都不带单位<br>
        （4）常用属性：<br>
        element.offsetParent：返回该元素带有定位的父级元素，如果父级都没有定位则返回body<br>
        element.offsetTop：返回元素相对带有定位父元素上方的偏移<br>
        element.offsetLeft：返回元素相对带有定位父元素左边框的偏移<br>
        element.offsetWidth：返回自身包括padding、边框、内容区的宽度，返回数值不带单位<br>
        element.offsetHeight：返回自身包括padding、边框、内容区的高度，返回数值不带单位<br>
        （5）offset和style区别<br>
        offset：<br>
        可以得到任意样式表中的样式值<br>
        获得的数值是没有单位的<br>
        包含padding+border+width<br>
        是只读属性，只能获取不能赋值<br>
        所以，获取元素大小、位置，用offset更合适<br>
        style：<br>
        只能得到行内样式的样式值<br>
        获得的是带有单位的字符串<br>
        不包含padding和border值<br>
        是可读写属性，可以获取也可以赋值<br>
        所以，要给元素更改值，则需要用style改变<br>
    </p>
    <h5>2.元素可视区client系列</h5>
    <p>
        使用client系列的相关属性来获取元素可视区的相关信息，可以动态的得到该元素的边框大小、元素大小等<br>
        （1）常用属性：<br>
        element.clientTop：返回元素边框的大小<br>
        element.clientLeft：返回元素左边框的大小<br>
        element.clientWidth：返回自身包括padding、内容区的宽度，不含边框，返回数值不带单位<br>
        element.clientHeight：返回自身包括padding、内容区的高度，不含边框，返回数值不带单位<br>

    </p>
    <h5>立即执行函数</h5>
    <p>
        1.立即执行函数最大的作用就是 独立创建了一个作用域，不需要调用，立马能够自己执行的函数<br>
        2.写法: 也可以传递参数进来<br>
        （1）(function (形参) {})(实参);<br>
        （2）(function(形参){}(实参));<br>
        3.注意：<br>
        多个立即执行函数必须用";"分隔<br>
        第二个小括号可以看做是调用函数<br>
        里面所有的变量都是局部变量，不会有命名冲突的情况<br>
    </p>
    <h5>3.元素滚动scroll系列</h5>
    <p>
        使用scroll系列的属性可以动态的到该元素的大小，滚动距离<br>
        （1）常用属性：<br>
        element.scrollTop：返回被卷去的上侧距离，返回数值不带单位<br>
        element.scrollLeft：返回被卷去的左侧距离，返回数值不带单位<br>
        element.scrollWidth：根据自身实际的宽度，不含边框，返回数值不带单位<br>
        element.scrollHeight：根据自身实际的高度，不含边框，返回数值不带单位<br>
        （2）scroll滚动事件 当滚动条发生变化会触发的事件<br>
        如果浏览器高（或宽）度不足以显示整个页面时，会自动出现滚动条，或者内容超出盒子 手动设置overflow:auto，<br>
        当拖动滚动条时，页面上面被隐藏掉的高度，称为卷去的头部，滚动条在滚动时会触发onscroll事件<br>
        （3）页面滚动距离：可以通过window.pageYOffset 获得，如果是被卷去的左侧 window.pageXOffset<br>
    </p>
    <h5>
        4.三大系列总结<br>
        主要用法：<br>
        （1）offset系列：主要用于获取元素的位置 offsetLeft、offsetTop<br>
        （2）client系列：主要用于获取元素的大小 clientLeft、clientTop<br>
        （3）scroll系列：主要用于获取滚动距离 scrollLeft、scrollTop<br>
        （4）注意：页面上下滚动距离window.pageYOffset，左右滚动距离window.pageXOffset<br>
    </h5>
    <p>
        5.mouseenter 和 mouseover 的区别<br>
        （1）mouseenter<br>
        鼠标只会经过自身盒子会触发<br>
        因为mouseenter不会冒泡<br>
        跟mouseleave 鼠标离开事件 搭配使用，同样不会冒泡<br>
        （2）mouseover<br>
        鼠标经过自身盒子会触发，经过子盒子还会触发<br>
    </p>
    <h4>十六、动画函数封装</h4>
    <p>
        1.核心原理：通过定时器setInterval()不断移动盒子位置<br>
        （1）实现步骤：<br>
        获得盒子位置-><br>
        让盒子在当前位置加上1个移动距离-><br>
        利用定时器不断重复这个操作-结束定时器的条件-><br>
        注意此元素需要添加定位，才能使用element.style.left<br>
    </p>
    <p>
        2.动画函数简单封装<br>
        （1）注意函数需要传递2个参数：动画对象 和 移动到的距离<br>
        （2）语法：<br>
        function animate(obj目标对象, target目标位置) {定时器函数}<br>
    </p>
    <p>
        3.给不同元素记录不同定时器<br>
        （1）如果多个元素都使用这个动画函数，每次都要var声明定时器，可以给不同的元素使用不同的定时器<br>
        简单理解：自己专门用自己的定时器<br>
        （2）核心原理：利用JS是一门动态语言，可以很方便的给当前对象添加属性<br>
        （3）不用var声明定时器，而是给不同的元素指定不同的定时器 obj.timer<br>
        （4）当不断点击按钮，这个元素会越来越快，因为开启了太多的定时器<br>
        解决方案就是 让元素只有一个定时器执行<br>
        先清除之前的定时器，只保留当前的一个定时器执行<br>
        clearInterval(obj.timer);<br>
    </p>
    <p>
        4.缓动动画原理<br>
        （1）让元素运动速度有所变化，最常见的是让速度慢慢停下来<br>
        （2）思路：<br>
        让盒子每次移动的距离慢慢编写，速度就会慢慢落下来-><br>
        核心算法：（目标值-现在的位置）/ 10，作为每次移动距离步长-><br>
        停止的条件：让当前盒子位置等于目标位置就停止定时器:obj.offsetLeft == target-><br>
        注意步长值需要取整<br>
        （3）区别：<br>
        匀速动画：盒子是当前的位置+固定的值<br>
        缓动动画：盒子当前位置+变化的值(（目标值-现在的位置）/10):(target - obj.offsetLeft) / 10<br>
    </p>
    <p>
        5.缓动动画多个目标值之间移动<br>
        （1）把步长值改为整数 不要出现小数<br>
        （2）如果是正值，则往大了取整；如果是负值，则往小了取整<br>
        step > 0 ? Math.ceil(step) : Math.floor(step);<br>

    </p>
    <p>
        6.动画函数添加回调函数<br>
        （1）原理：函数作为一个参数，传到另一个函数里面，当那个函数执行完后，再执行穿进去的这个函数。<br>
        （2）回调函数写到定时器结束的位置<br>
    </p>
    <p>
        7.动画函数封装<br>
        （1）封装到单独JS文件中，使用时引用这个JS文件即可<br>
        （2）调用时：<br>
        animate(obj, target, function(){});<br>
    </p>
    <p>
        8.节流阀<br>
        防止轮播图连续点击造成播放过快<br>
        （1）目的：当上一个函数动画内容执行完毕，再去执行下一个函数动画，让事件无法连续触发<br>
        （2）核心思路：利用回调函数，添加一个变量来控制，锁住函数和解锁函数<br>
        （3）分析：<br>
        开始先设置一个变量 var flag=true；<br>
        if(flag){flag = false；do something} 关闭水龙头<br>
        利用回调函数，动画执行完毕，flag=true 打开水龙头<br>
    </p>
    <h4>十七、移动端网页特效</h4>
    <p>
        1.触屏事件<br>
        （1）触屏事件touch（触摸事件）android和IOS都有<br>
        移动端兼容性较好，不需要考虑JS兼容性问题，可以放心使用原生JS书写效果<br>
        （2）touch:用于对屏幕或触控板操作<br>
        （3）事件：<br>
        touchstart：触摸到一个DOM元素时触发<br>
        touchmove：在一个DOM元素上滑动时触发<br>
        touchend：从一个DOM元素上移开时触发<br>
    </p>
    <p>
        2.触摸事件对象（touchEvent）<br>
        描述在触摸后的状态变化的事件。主要用于描述一个或者多个出点，使开发者可以检测触点的移动，触点的增加/减少 等等<br>
        因为一般都是触摸元素，所以经常使用的是 targetTouches
        （1）三个常用对象：<br>
        touches：正在触摸屏幕的所有手指的一个列表<br>
        targetTouches：正在触摸当前DOM元素上手指的一个列表<br>
        如果监听的是一个DOM元素，与touches是一样的<br>
        changedTouches：手指状态发生变化的列表，从无到有，从有到无变化<br>
        当手指离开屏幕时，就没有touches和targetTouches 列表，但是会有 changedTouches<br>
        （2）targetTouches[0] 可以得到正在触摸DOM元素的第一个手指的相关信息<br>
    </p>
    <p>
        3.移动端拖动元素<br>
        （1）touchstart、touchmove、touchend 可以实现拖动元素<br>
        （2）获取拖动元素当前手指的坐标值：targetTouches[0]里面的 pageX 和 pageY<br>
        （3）原理：手指移动中，计算出手指移动的距离。然后用盒子原理的位置 + 手指移动的距离<br>
        （4）手指移动的距离：手指滑动中的位置 - 手指刚开始触摸的位置<br>
        拖动三部曲：<br>
        touchstart：获取手指初始坐标，同时获得盒子原来的位置<br>
        touchmove：计算手指滑动的距离，并且移动盒子<br>
        touchend：<br>
        注意：手指移动也会触发滚动屏幕 所以需要阻止默认的屏幕滚动的时候：e.preventDefault();<br>
    </p>
    <p>
        4.transitionend 等过渡完成之后再去判断，监听过渡完成的事件<br>
    </p>
    <p>
        5.classList<br>
        H5新增属性，返回元素的类名。IE10以上支持<br>
        该属性用于元素中添加、移动、切换CSS类，方法如下<br>
        （1）添加类：element.classList.add('类名');<br>
        在后面追加类名 不会覆盖以前的类名 注意前面不需要加“.”<br>
        （2）移除类：element.classList.remove('类名');<br>
        （3）切换类：element.classList.toggle('类名');<br>
        没有就添加类名，有则去掉类名<br>
    </p>
    <p>
        6.click 延时解决方案<br>
        移动端 click事件 会有300ms的延时，原因是移动端屏幕双击会缩放（double tap to zoom）页面<br>
        解决方案：<br>
        （1）禁用缩放。浏览器禁用默认的双击缩放行为并且去掉300ms的点击延迟<br>
        meta的content中添加 “user-scalable=no”<br>
        （2）利用touch事件自己封装这个事件解决300ms延迟<br>
        原理：<br>
        当手指触摸屏幕，记录当前触摸时间<br>
        当手指离开屏幕，用哪个离开的时间减去触摸的时间<br>
        如果时间小于150ms，并且没有滑动过屏幕，那么我们就定义为点击<br>
        （3）常用插件<br>
        fastclick插件 解决300ms延迟<br>
        地址：github.com/ftlabs/fastclick<br>
    </p>
    <p>
        7. 插件使用<br>
        （1）Swiper-轮播图插件，地址：www.swiper.com.cn<br>
        （2）superslide ,地址：www.superslide2.com<br>
        （3）iscroll ,地址：github.com/cubiq/iscroll<br>
        （4）视频插件，zy.media.js
        （5）插件使用总结：<br>
        确认插件实现功能<br>
        官网查看使用说明<br>
        下载插件<br>
        打开demo实例文件，查看需要引入的相关文件，并且引入<br>
        复制demo中的结构html、样式css、js代码<br>
    </p>
    <p>
        8.移动端常用开发框架<br>
        框架：基于自身特点向用户提供一套较为完整的解决方案<br>
        Bootstrap、VUE、Angular、React等 既能开发PC端，也能开发移动端<br>
    </p>
    <h4>十八、本地储存</h4>
    <p>
        1.特性：<br>
        （1）数据存储在用户浏览器中<br>
        （2）设置、读取方便、甚至页面刷新、关闭也不丢失数据<br>
        （3）容量较大，sessionStorage约5M、localStorage约20M<br>
        （4）只能存储字符串，可将对象JSON。stringify()编码后储存<br>
    </p>
    <p>
        2.window.sessionStorage<br>
        （1）生命周期为关闭浏览器窗口<br>
        （2）在同一个窗口（页面）下数据可以共享<br>
        （3）以键值对的形式存储使用<br>
        储存数据：sessionStorage.setItem(key,value)<br>
        获取数据：sessionStorage.getItem(key)<br>
        删除数据：sessionStorage.removeItem(key)<br>
        删除所有数据：sessionStorage.clear() 慎用此功能！<br>
    </p>
    <p>
        3.window.localStorage<br>
        （1）生命周期周期永久生效，除非手动删除，否则关闭页面也会存在<br>
        （2）可以多窗口（页面）共享（同一浏览器可以共享）<br>
        （3）以键值对的形式存储使用<br>
        储存数据：localStorage.setItem(key,value)<br>
        获取数据：localStorage.getItem(key)<br>
        删除数据：localStorage.removeItem(key)<br>
        删除所有数据：localStorage.clear() 慎用此功能！<br>
    </p>
</body>

</html>